/**
This module creates a drawer (box).
The box itself can have rounded corners/edges on the innside/outside.
This serves two purposes:
    1. Better Design/Looks - rounded outside edges influence the appearence. 
    2. Stability of the drawer - rounded inside corners make the whole drawer more rugged.
*/

// -> increase the number for smoother corners and edges
$fn = 20;
// -> length of front of the drawer
length = 210;
// -> width (=length of sides) of the drawer
width  = 250; 
// -> heigth of the drawer
height = 100;
// -> thickness of the walls
wallthickness = 2.0;
// -> thickness of the bottom
bottomthickness = 2.0;
// -> corner radius on the inside of the box (0 for unrounded inside corners)
cornerRadius = 3.0;
// -> edge radius on the outside of the box (0 for unrounded outside edges)
edgeRadius = 1.0;
// -> coordinates where the center of the handle is located.
location=[length/2, 0, (height/5)*4]; 
// -> diameter of the hole used as drawer handle
handleDiameter=20; 

// this is the openscad way to pass objects as parameters to modules :)
makeHandleWithHole(handleDiameter, location, wallthickness)
{
drawer(length, width, height, wallthickness, bottomthickness, cornerRadius, edgeRadius);
}
//drawer(length, width, height, 
//              wallthickness=wallthickness, 
//              cornerRadius=40,
//              bottomthickness=1.2);

/**
* module creates a drawer 
* @param length: length of front of the drawer
* @param width: width (=length of sides) of the drawer
* @param height: heigth of the drawer
* @param wallthickness: thickness of the walls
* @param bottomthickness: thickness of the bottom
* @param cornerRadius: corner radius on the inside of the box (0 for unrounded inside corners)
* @param edgeRadius: edge radius on the outside of the box (0 for unrounded outside edges)
*/
module drawer(length, width, height, 
              wallthickness=1.2, 
              bottomthickness=1.2, 
              cornerRadius=5, 
              edgeRadius=5)
{
    // check parameters
    assert(length>0, "Length of front cannot be zero or less!");
    assert(width>0, "Length of sides cannot be zero or less!");
    assert(height>0, "Height of drawer cannot be zero or less!");
    assert(wallthickness>0, "Thickness of the walls cannot be zero or less!");
    assert(bottomthickness>0, "Thickness of the bottom cannot be zero or less!");
    assert(cornerRadius>=0, "Radius of the inside corners cannot be less than zero!");
    assert(edgeRadius>=0, "Radius of the outside edges cannot be less than zero!");
    assert(edgeRadius<=cornerRadius, "Radius of the outside edges cannot be smaller than radius of inside corners!");

    // cut out inner box from outer box
    difference()
    {
        // outer box
        if (edgeRadius > 0)   // box with rounded edges
        { 
            roundedBox(length, width, height, edgeRadius);
        }
        else  // straight box without rounded edges
        {
            cube([length, width, height]);
        }
        
        // inner box
        translate([wallthickness, wallthickness, bottomthickness])
        if (cornerRadius > 0)   // box with rounded edges
        { 
            roundedBox(length-2*wallthickness, width-2*wallthickness, height, cornerRadius);
        }
        else  // straight box without rounded edges
        {
            cube([length-2*wallthickness, width-2*wallthickness, height]);
        }
    }
}
/**
* @param handleDiameter: diameter of hole that serves as handle
* @param location: coordinates of center of hole
* @param wallthickness: thickness needed for cutting hole into wall 
*/
module makeHandleWithHole(handleDiameter, location, wallthickness)
{
    difference()
    {
        children(0);
        translate([location[0],wallthickness-0.1,location[2]]) 
            rotate([90, 0, 0]) 
                cylinder(2*wallthickness, d=handleDiameter, center=true, $fn=60);
    }
}

// creates a box with rounded edges all around except on the top
module roundedBox(length, width, height, radius)
{
    translate([radius,radius,radius])
    hull() 
    {
        sphere(radius);
        translate([length-2*radius, 0, 0])              sphere(radius);
        translate([length-2*radius, width-2*radius, 0]) sphere(radius);
        translate([0, width-2*radius, 0])               sphere(radius);
        
        translate([0, 0, height-radius])                            halfSphere(radius);
        translate([length-2*radius, 0, height-radius])              halfSphere(radius);
        translate([length-2*radius, width-2*radius, height-radius]) halfSphere(radius);
        translate([0, width-2*radius, height-radius])               halfSphere(radius);
    }
}

// creates half of a sphere
module halfSphere(radius)
{
    difference()
    {
        sphere(radius);
        translate([-1.5*radius, -1.5*radius, 0]) cube(3*radius);
    }
}
